/***************************************************************************/
/*                                                                         */
/*  t1cmap.c                                                               */
/*                                                                         */
/*    Type 1 character map support (body).                                 */
/*                                                                         */
/*  Copyright 2002, 2003, 2006, 2007 by                                    */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include "t1cmap.h"

#include FT_INTERNAL_DEBUG_H

#include "psauxerr.h"


/*************************************************************************/
/*************************************************************************/
/*****                                                               *****/
/*****          TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS           *****/
/*****                                                               *****/
/*************************************************************************/
/*************************************************************************/

static void
t1_cmap_std_init(T1_CMapStd cmap,
                 FT_Int is_expert)
{
    T1_Face face = (T1_Face)FT_CMAP_FACE(cmap);
    FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;


    cmap->num_glyphs = face->type1.num_glyphs;
    cmap->glyph_names = (const char* const*)face->type1.glyph_names;
    cmap->sid_to_string = psnames->adobe_std_strings;
    cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding
                        : psnames->adobe_std_encoding;

    FT_ASSERT(cmap->code_to_sid != NULL);
}


FT_CALLBACK_DEF(void)
t1_cmap_std_done(T1_CMapStd cmap)
{
    cmap->num_glyphs = 0;
    cmap->glyph_names = NULL;
    cmap->sid_to_string = NULL;
    cmap->code_to_sid = NULL;
}


FT_CALLBACK_DEF(FT_UInt)
t1_cmap_std_char_index(T1_CMapStd cmap,
                       FT_UInt32 char_code)
{
    FT_UInt result = 0;


    if (char_code < 256)
    {
        FT_UInt code, n;
        const char* glyph_name;


        /* convert character code to Adobe SID string */
        code = cmap->code_to_sid[char_code];
        glyph_name = cmap->sid_to_string(code);

        /* look for the corresponding glyph name */
        for (n = 0; n < cmap->num_glyphs; n++)
        {
            const char* gname = cmap->glyph_names[n];


            if (gname && gname[0] == glyph_name[0] &&
                ft_strcmp(gname, glyph_name) == 0)
            {
                result = n;
                break;
            }
        }
    }

    return result;
}


FT_CALLBACK_DEF(FT_UInt32)
t1_cmap_std_char_next(T1_CMapStd cmap,
                      FT_UInt32 * pchar_code)
{
    FT_UInt result = 0;
    FT_UInt32 char_code = *pchar_code + 1;


    while (char_code < 256)
    {
        result = t1_cmap_std_char_index(cmap, char_code);
        if (result != 0)
            goto Exit;

        char_code++;
    }
    char_code = 0;

Exit:
    *pchar_code = char_code;
    return result;
}


FT_CALLBACK_DEF(FT_Error)
t1_cmap_standard_init(T1_CMapStd cmap)
{
    t1_cmap_std_init(cmap, 0);
    return 0;
}


FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
t1_cmap_standard_class_rec =
{
    sizeof(T1_CMapStdRec),

    (FT_CMap_InitFunc)t1_cmap_standard_init,
    (FT_CMap_DoneFunc)t1_cmap_std_done,
    (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
    (FT_CMap_CharNextFunc)t1_cmap_std_char_next,

    NULL, NULL, NULL, NULL, NULL
};


FT_CALLBACK_DEF(FT_Error)
t1_cmap_expert_init(T1_CMapStd cmap)
{
    t1_cmap_std_init(cmap, 1);
    return 0;
}

FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
t1_cmap_expert_class_rec =
{
    sizeof(T1_CMapStdRec),

    (FT_CMap_InitFunc)t1_cmap_expert_init,
    (FT_CMap_DoneFunc)t1_cmap_std_done,
    (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
    (FT_CMap_CharNextFunc)t1_cmap_std_char_next,

    NULL, NULL, NULL, NULL, NULL
};


/*************************************************************************/
/*************************************************************************/
/*****                                                               *****/
/*****                    TYPE1 CUSTOM ENCODING CMAP                 *****/
/*****                                                               *****/
/*************************************************************************/
/*************************************************************************/


FT_CALLBACK_DEF(FT_Error)
t1_cmap_custom_init(T1_CMapCustom cmap)
{
    T1_Face face = (T1_Face)FT_CMAP_FACE(cmap);
    T1_Encoding encoding = &face->type1.encoding;


    cmap->first = encoding->code_first;
    cmap->count = (FT_UInt)(encoding->code_last - cmap->first);
    cmap->indices = encoding->char_index;

    FT_ASSERT(cmap->indices != NULL);
    FT_ASSERT(encoding->code_first <= encoding->code_last);

    return 0;
}


FT_CALLBACK_DEF(void)
t1_cmap_custom_done(T1_CMapCustom cmap)
{
    cmap->indices = NULL;
    cmap->first = 0;
    cmap->count = 0;
}


FT_CALLBACK_DEF(FT_UInt)
t1_cmap_custom_char_index(T1_CMapCustom cmap,
                          FT_UInt32 char_code)
{
    FT_UInt result = 0;


    if ((char_code >= cmap->first) &&
        (char_code < (cmap->first + cmap->count)))
        result = cmap->indices[char_code];

    return result;
}


FT_CALLBACK_DEF(FT_UInt32)
t1_cmap_custom_char_next(T1_CMapCustom cmap,
                         FT_UInt32 * pchar_code)
{
    FT_UInt result = 0;
    FT_UInt32 char_code = *pchar_code;


    ++char_code;

    if (char_code < cmap->first)
        char_code = cmap->first;

    for (; char_code < (cmap->first + cmap->count); char_code++)
    {
        result = cmap->indices[char_code];
        if (result != 0)
            goto Exit;
    }

    char_code = 0;

Exit:
    *pchar_code = char_code;
    return result;
}


FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
t1_cmap_custom_class_rec =
{
    sizeof(T1_CMapCustomRec),

    (FT_CMap_InitFunc)t1_cmap_custom_init,
    (FT_CMap_DoneFunc)t1_cmap_custom_done,
    (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index,
    (FT_CMap_CharNextFunc)t1_cmap_custom_char_next,

    NULL, NULL, NULL, NULL, NULL
};


/*************************************************************************/
/*************************************************************************/
/*****                                                               *****/
/*****            TYPE1 SYNTHETIC UNICODE ENCODING CMAP              *****/
/*****                                                               *****/
/*************************************************************************/
/*************************************************************************/

FT_CALLBACK_DEF(const char*)
t1_get_glyph_name(T1_Face face,
                  FT_UInt idx)
{
    return face->type1.glyph_names[idx];
}


FT_CALLBACK_DEF(FT_Error)
t1_cmap_unicode_init(PS_Unicodes unicodes)
{
    T1_Face face = (T1_Face)FT_CMAP_FACE(unicodes);
    FT_Memory memory = FT_FACE_MEMORY(face);
    FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;


    return psnames->unicodes_init(memory,
                                  unicodes,
                                  face->type1.num_glyphs,
                                  (PS_GetGlyphNameFunc) & t1_get_glyph_name,
                                  (PS_FreeGlyphNameFunc)NULL,
                                  (FT_Pointer)face);
}


FT_CALLBACK_DEF(void)
t1_cmap_unicode_done(PS_Unicodes unicodes)
{
    FT_Face face = FT_CMAP_FACE(unicodes);
    FT_Memory memory = FT_FACE_MEMORY(face);


    FT_FREE(unicodes->maps);
    unicodes->num_maps = 0;
}


FT_CALLBACK_DEF(FT_UInt)
t1_cmap_unicode_char_index(PS_Unicodes unicodes,
                           FT_UInt32 char_code)
{
    T1_Face face = (T1_Face)FT_CMAP_FACE(unicodes);
    FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;


    return psnames->unicodes_char_index(unicodes, char_code);
}


FT_CALLBACK_DEF(FT_UInt32)
t1_cmap_unicode_char_next(PS_Unicodes unicodes,
                          FT_UInt32 * pchar_code)
{
    T1_Face face = (T1_Face)FT_CMAP_FACE(unicodes);
    FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;


    return psnames->unicodes_char_next(unicodes, pchar_code);
}


FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
t1_cmap_unicode_class_rec =
{
    sizeof(PS_UnicodesRec),

    (FT_CMap_InitFunc)t1_cmap_unicode_init,
    (FT_CMap_DoneFunc)t1_cmap_unicode_done,
    (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index,
    (FT_CMap_CharNextFunc)t1_cmap_unicode_char_next,

    NULL, NULL, NULL, NULL, NULL
};


/* END */